#ifndef RAPIDXML_UTILS_HPP_INCLUDED
#define RAPIDXML_UTILS_HPP_INCLUDED

// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
// ! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
// ! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.

#include "rapidxml.hpp"
#include <vector>
#include <string>
#include <fstream>
#include <stdexcept>

namespace rapidxml
{
	// ! Represents data loaded from a file
	template<class Ch = char>
	class file
	{
public:

		// ! Loads file into the memory. Data will be automatically destroyed by the destructor.
		// ! \param filename Filename to load.
		file( const char *filename )
		{
			using namespace std;

			// Open stream
			basic_ifstream<Ch> stream( filename, ios::binary );
			if (!stream)
				throw runtime_error( string(
						"cannot open file " ) +
					filename );
			stream.unsetf( ios::skipws );

			// Determine stream size
			stream.seekg( 0, ios::end );
			size_t size = stream.tellg();
			stream.seekg( 0 );

			// Load data and add terminating 0
			m_data.resize( size + 1 );
			stream.read( &m_data.front(),
				static_cast<streamsize>( size ));
			m_data[size] = 0;
		}

		// ! Loads file into the memory. Data will be automatically destroyed by the destructor
		// ! \param stream Stream to load from
		file( std::basic_istream<Ch> &stream )
		{
			using namespace std;

			// Load data and add terminating 0
			stream.unsetf( ios::skipws );
			m_data.assign( istreambuf_iterator<Ch>(
					stream ), istreambuf_iterator<Ch>());
			if (stream.fail() || stream.bad())
				throw runtime_error( "error reading stream" );
			m_data.push_back( 0 );
		}

		// ! Gets file data.
		// ! \return Pointer to data of file.
		Ch *data()
		{
			return &m_data.front();
		}

		// ! Gets file data.
		// ! \return Pointer to data of file.
		const Ch *data() const
		{
			return &m_data.front();
		}

		// ! Gets file data size.
		// ! \return Size of file data, in characters.
		std::size_t size() const
		{
			return m_data.size();
		}

private:

		std::vector<Ch> m_data; // File data
	};

	// ! Counts children of node. Time complexity is O(n).
	// ! \return Number of children of node
	template<class Ch>
	inline std::size_t count_children( xml_node<Ch> *node )
	{
		xml_node<Ch> *child = node->first_node();
		std::size_t   count = 0;
		while (child)
		{
			++count;
			child = child->next_sibling();
		}
		return count;
	}

	// ! Counts attributes of node. Time complexity is O(n).
	// ! \return Number of attributes of node
	template<class Ch>
	inline std::size_t count_attributes( xml_node<Ch> *node )
	{
		xml_attribute<Ch> *attr = node->first_attribute();
		std::size_t        count = 0;
		while (attr)
		{
			++count;
			attr = attr->next_attribute();
		}
		return count;
	}
}

#endif
